[shadow] Be smarter about what we check to avoid unnecessary brute-force searches
authorGeorge Dunlap <gdunlap@xensource.com>
Wed, 19 Sep 2007 10:58:04 +0000 (11:58 +0100)
committerGeorge Dunlap <gdunlap@xensource.com>
Wed, 19 Sep 2007 10:58:04 +0000 (11:58 +0100)
The old code checked only if the page was still a pagetable before
doing a brute-force search, rather than checking if it was still
shadowed as the type indicated.  This meant that if a page was shadowed
as two different types, it was guaranteed to do a full brute-force search
even if all references could be found by up-pointers.

This checks the proper thing so that it will only do a brute-force if
necessary.

It also re-orders the unshadows so that higher levels are done first.  In
many cases, lower-level shadows will be destroyed in the process of
higher-level shadows being destroyed, again saving brute-force searches.

xen/arch/x86/mm/shadow/common.c

index 4d1bac1516bf37cb52082f64d7ddb603ce253b87..04bc55deb4b1a2d0b1fbcac4fb0b1591547ee731 100644 (file)
@@ -1981,7 +1981,6 @@ void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int fast, int all)
 {
     struct page_info *pg = mfn_to_page(gmfn);
     mfn_t smfn;
-    u32 sh_flags;
     int do_locking;
     unsigned char t;
     
@@ -2065,42 +2064,46 @@ void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int fast, int all)
 
     /* Search for this shadow in all appropriate shadows */
     perfc_incr(shadow_unshadow);
-    sh_flags = pg->shadow_flags;
 
     /* Lower-level shadows need to be excised from upper-level shadows.
      * This call to hash_foreach() looks dangerous but is in fact OK: each
      * call will remove at most one shadow, and terminate immediately when
      * it does remove it, so we never walk the hash after doing a deletion.  */
-#define DO_UNSHADOW(_type) do {                                 \
-    t = (_type);                                                \
-    smfn = shadow_hash_lookup(v, mfn_x(gmfn), t);               \
-    if ( unlikely(!mfn_valid(smfn)) )                           \
-    {                                                           \
-        SHADOW_ERROR(": gmfn %#lx has flags 0x%"PRIx32          \
-                     " but no type-0x%"PRIx32" shadow\n",       \
-                     mfn_x(gmfn), sh_flags, t);                 \
-        break;                                                  \
-    }                                                           \
-    if ( sh_type_is_pinnable(v, t) )                            \
-        sh_unpin(v, smfn);                                      \
-    else                                                        \
-        sh_remove_shadow_via_pointer(v, smfn);                  \
-    if ( (pg->count_info & PGC_page_table) && !fast )           \
-        hash_foreach(v, masks[t], callbacks, smfn);             \
+#define DO_UNSHADOW(_type) do {                                         \
+    t = (_type);                                                        \
+    if( !(pg->count_info & PGC_page_table)                              \
+        || !(pg->shadow_flags & (1 << t)) )                             \
+        break;                                                          \
+    smfn = shadow_hash_lookup(v, mfn_x(gmfn), t);                       \
+    if ( unlikely(!mfn_valid(smfn)) )                                   \
+    {                                                                   \
+        SHADOW_ERROR(": gmfn %#lx has flags 0x%"PRIx32                  \
+                     " but no type-0x%"PRIx32" shadow\n",               \
+                     mfn_x(gmfn), (uint32_t)pg->shadow_flags, t);       \
+        break;                                                          \
+    }                                                                   \
+    if ( sh_type_is_pinnable(v, t) )                                    \
+        sh_unpin(v, smfn);                                              \
+    else                                                                \
+        sh_remove_shadow_via_pointer(v, smfn);                          \
+    if( !fast                                                           \
+        && (pg->count_info & PGC_page_table)                            \
+        && (pg->shadow_flags & (1 << t)) )                              \
+        hash_foreach(v, masks[t], callbacks, smfn);                     \
 } while (0)
 
-    if ( sh_flags & SHF_L1_32 )   DO_UNSHADOW(SH_type_l1_32_shadow);
-    if ( sh_flags & SHF_L2_32 )   DO_UNSHADOW(SH_type_l2_32_shadow);
+    DO_UNSHADOW(SH_type_l2_32_shadow);
+    DO_UNSHADOW(SH_type_l1_32_shadow);
 #if CONFIG_PAGING_LEVELS >= 3
-    if ( sh_flags & SHF_L1_PAE )  DO_UNSHADOW(SH_type_l1_pae_shadow);
-    if ( sh_flags & SHF_L2_PAE )  DO_UNSHADOW(SH_type_l2_pae_shadow);
-    if ( sh_flags & SHF_L2H_PAE ) DO_UNSHADOW(SH_type_l2h_pae_shadow);
+    DO_UNSHADOW(SH_type_l2h_pae_shadow);
+    DO_UNSHADOW(SH_type_l2_pae_shadow);
+    DO_UNSHADOW(SH_type_l1_pae_shadow);
 #if CONFIG_PAGING_LEVELS >= 4
-    if ( sh_flags & SHF_L1_64 )   DO_UNSHADOW(SH_type_l1_64_shadow);
-    if ( sh_flags & SHF_L2_64 )   DO_UNSHADOW(SH_type_l2_64_shadow);
-    if ( sh_flags & SHF_L2H_64 )  DO_UNSHADOW(SH_type_l2h_64_shadow);
-    if ( sh_flags & SHF_L3_64 )   DO_UNSHADOW(SH_type_l3_64_shadow);
-    if ( sh_flags & SHF_L4_64 )   DO_UNSHADOW(SH_type_l4_64_shadow);
+    DO_UNSHADOW(SH_type_l4_64_shadow);
+    DO_UNSHADOW(SH_type_l3_64_shadow);
+    DO_UNSHADOW(SH_type_l2h_64_shadow);
+    DO_UNSHADOW(SH_type_l2_64_shadow);
+    DO_UNSHADOW(SH_type_l1_64_shadow);
 #endif
 #endif